#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include<set>
namespace bitpr
{
    namespace server
    {

        class ProviderManager
        {

        public:
            using ptr = std::shared_ptr<ProviderManager>;
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                BaseConnection::ptr conn;
                std::mutex _mutex;
                Address host;
                std::vector<std::string> methods;
                Provider(const BaseConnection::ptr &c, const Address &h);
                void appendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.emplace_back(method);
                }
            };
            // 服务提供者提供服务调用
            void addProvide(const BaseConnection::ptr &c, const Address &h, const std::string &method)
            {
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        provider = it->second;
                    }
                    else
                    {
                        // 修改这个_conn数组
                        provider = std::make_shared<Provider>(c, h);
                        _conns.insert(std::make_pair(c, provider));
                    }
                    // 修改这个providers数组
                    // 我感觉他的代码试错的,先找到这个提供者,应该插入到一个provider数组里面的
                    auto &providers = _providers[method];
                    providers.insert(provider);//vector的insert参数(下标,插入元素);
                }
                // 提供者里面添加可以提供的服务
                provider->appendMethod(method);
            }
          
            // 断开连接时,获取信息---用于线下通知
            void delProvider(const BaseConnection::ptr &c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    // 当前断开连接的不是一个服务提供者
                    return;
                }
                // 如果是提供者,就要看删除当前服务提供者
                for (auto &method : it->second->methods)
                {
                    auto &providers = _providers[method];
                    providers.erase(it->second); // 出错了,要传迭代器
                }
                // 删除链接和服务提供者的关联
                _conns.erase(it);
            }
            Provider::ptr getProvider(const BaseConnection::ptr &c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it != _conns.end())
                {
                    return it->second;
                }
                return Provider::ptr();
            }
            std::vector<Address> methodHosts(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _providers.find(method);
                if (it == _providers.end())
                {
                    return std::vector<Address>();
                }
                std::vector<Address> result;
                // 把所有有这个方法的主机号发送出去
                for (auto &provider : it->second)
                {
                    result.push_back(provider->host);
                }
                return result;
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
        };
        class DiscoverManager
        {

        public:
            using ptr = std::shared_ptr<DiscoverManager>;
            struct Discoverer
            {

                using ptr = std::shared_ptr<Discoverer>;
                std::mutex _mutex;
                BaseConnection::ptr conn;         // 发现这个关联的客户端连接
                std::vector<std::string> methods; // 发现的服务
                Discoverer(const BaseConnection::ptr &c);
                void appendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.push_back(method);
                }
            };
            Discoverer::ptr addDiscoverer(const BaseConnection::ptr &c, const std::string &method)
            {
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        discoverer = it->second;
                    }
                    else
                    {
                        discoverer = std::make_shared<Discoverer>(c);
                        _conns.insert(std::make_pair(c, discoverer));
                    }
                    auto &discoverers = _discoverers[method];
                    discoverers.insert(discoverer);
                }
                discoverer->appendMethod(method);
                return discoverer;
            }
            void delDiscoverer(const BaseConnection::ptr &c)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    // 没有找到连接对应的发现者信息，代表客户端不是一个服务发现者
                    return;
                }
                for (auto &method : it->second->methods)
                {
                    auto discoverers = _discoverers[method];
                    discoverers.erase(it->second);
                }
                _conns.erase(it);
            }
            // 有一个新的服务提供者上线,进行上线通知
            void onlineNotify(const std::string &method, const Address &host)
            {
                return notify(method, host, ServiceOptype::SERVICE_ONLINE);
            }
            // 有一个新的服务提供者上线,进行下线
            void offlineNotify(const std::string &method, const Address &host)
            {
                return notify(method, host, ServiceOptype::SERVICE_OFFLINE);
            }

        private:
            // 1 找 2通知发现这个方法的客户端
            void notify(const std::string &method, const Address &host, ServiceOptype optype)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _discoverers.find(method);
                if (it == _discoverers.end())
                {
                    // 这代表这个服务当前没有发现者
                    return;
                }
                auto msg_req = MessageFactory::create<ServiceRequest>();
                msg_req->setId(UUID::uuid());
                msg_req->setMType(MType::REQ_SERVICE);
                msg_req->setMethod(method);
                msg_req->setHost(host);
                msg_req->setOptype(optype);
                for (auto &discoverer : it->second)
                {
                    discoverer->conn->send(msg_req);
                }
            }
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _discoverers;
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;
        };
        class PDManager
        {

        public:
            using ptr = std::shared_ptr<PDManager>;
            PDManager():_providers(std::make_shared<ProviderManager>()),
            _discoverers(std::make_shared<DiscoverManager>()){}
            void onServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg){
                //服务注册 服务请求
                ServiceOptype optype=msg->optype();
                if(optype==ServiceOptype::SERVICE_REGISTRY){
                    //服务注册
                    //新增提供者 2 进行服务上线的通知
                    ILOG("%s:%d注册服务 %s",msg->host().first.c_str(),msg->host().second,msg->method().c_str());
                    _providers->addProvide(conn,msg->host(),msg->method());
                    _discoverers->onlineNotify(msg->method(),msg->host());
                    return registryResponse(conn,msg);

                }else if(optype==ServiceOptype::SERVICE_DISCOVERY){
                    //1新增服务发现者
                    ILOG("客户端进行%s",msg->method().c_str());
                    _discoverers->addDiscoverer(conn,msg->method());
                    return discoveryResponse(conn,msg);
                }else  {
                        ELOG("收到服务操作请求，但是操作类型错误！");
                        return errorResponse(conn, msg);
                    }
            }
            void onConnShutdown(const BaseConnection::ptr &conn){
                //服务下线1 找到这个发现这个服务的发现者给出通知 2 删除这个提供者的联系,删除发现者
                auto provider=_providers->getProvider(conn);
                if(provider.get()!=nullptr){
                    ILOG("%s: %d服务下线",provider->host.first.c_str(),provider->host.second);
                    for(auto& method:provider->methods){
                        _discoverers->offlineNotify(method,provider->host);
                    }
                    _providers->delProvider(conn);
                }
                _discoverers->delDiscoverer(conn);

            }

        private:
           void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
                    auto msg_rsp = MessageFactory::create<ServiceResponse>();
                    msg_rsp->setId(msg->rid());
                    msg_rsp->setMType(MType::RSP_SERVICE);
                    msg_rsp->setRCode(RCode::RCODE_INVAILD_OPTYPE);
                    msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW);
                    conn->send(msg_rsp);
                }
                void registryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
                    auto msg_rsp = MessageFactory::create<ServiceResponse>();
                    msg_rsp->setId(msg->rid());
                    msg_rsp->setMType(MType::RSP_SERVICE);
                    msg_rsp->setRCode(RCode::RCODE_OK);
                    msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY);
                    conn->send(msg_rsp);
                }
                void discoveryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
                    auto msg_rsp = MessageFactory::create<ServiceResponse>();
                    msg_rsp->setId(msg->rid());
                    msg_rsp->setMType(MType::RSP_SERVICE);
                    msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVERY);
                    std::vector<Address> hosts = _providers->methodHosts(msg->method());
                    if (hosts.empty()) {
                        msg_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);
                        return conn->send(msg_rsp);
                    }   
                    msg_rsp->setRCode(RCode::RCODE_OK);
                    msg_rsp->setMethod(msg->method());
                    msg_rsp->setHost(hosts);
                    return conn->send(msg_rsp);
                }
            ProviderManager::ptr _providers;
            DiscoverManager::ptr _discoverers;
        };

    }
}